#include "StdAfx.h"
#include "CompilationEngine.h"

// helper function to compilationEngine
bool isMathOperation(char ch){
	switch(ch){
	case '+':
	case '-':
	case '*':
	case '/':
	case '&':
	case '|':
	case '<':
	case '>':
	case '=': return true;
	default: return false;
	}
}

// constructor for the compilation Engine
// this constructor also initialize the JackTokenizer
CompilationEngine::CompilationEngine(char *infilename)
	:tokenizerInstance(infilename)// initialize the Jack Tokenizer
{
	
	// tokenize the input file
	tokenizerInstance.tokenize();
	cout<< infilename << " tokenized successfully! \n";

	//Play around with the file names
	string outfilename=infilename;
	outfilename.erase(outfilename.size()-5,5);
	className=outfilename; //input name without extension.
	outfilename+=".vm";
	outfile.open(outfilename.c_str(), ios::out);

	//Init if/while counters
	ifCount=0;
	whileCount=0;
	
	//Need the class base name isolated, no path
	className.erase(0,className.find_last_of('\\')+1); 
}

CompilationEngine::~CompilationEngine(void)
{
	outfile.close();
}

// compile a complete class
bool CompilationEngine::CompileClass()
{
	//start parsing:
	// get the tokenized file 
	string next=tokenizerInstance.getTokenizedFile();
	string currentToken=next;
	// erase end of string after "class"
	currentToken.erase(5,currentToken.size()-5);
	// check if we really have "class" as expected
	if(currentToken=="class"){
		// set the current token to class type
		tokenizerInstance.setCurrentToken("class");
		// increment the ptr
		tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr() +5);
		// increment the next too (its gona be currentToken)
		next.erase(0,5);
		currentToken=next;
		// erase from the next bracket to the end
		currentToken.erase(currentToken.find("{"), currentToken.size()-currentToken.find("{"));
		tokenizerInstance.setCurrentToken(currentToken);
		// check the token type handle the identifier
		if(tokenizerInstance.tokenType()==IDENTIFIER)
		{
			
			// set the ptr to next bracket
			tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr() + next.find("{")+1);
			next.erase(0,(next.find("{")+1));
			// the main while - go over everything vars or rutines
			while(next.size()>1)
			{
				if (!CompileClassVarDec())
				{
					// something went wrong in classvardec
					return false;
				}
				next=tokenizerInstance.getTokenizedFile();
				next.erase(0,tokenizerInstance.getTokenPtr());
				if (!CompileSubroutine())
				{
					// something went wrong in subrutine compile
					return false;
				}				
				next=tokenizerInstance.getTokenizedFile();
				next.erase(0,tokenizerInstance.getTokenPtr());
			}
			// find the closing bracket of the class
			if(next=="}")
			{
				tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
				next.erase(0,1);
				return true;
			}
			// compilation error
			cout << "compilation error : } expected\n";
			return false;
		}
		// compilation error
		cout << "compilation error : Identifier expected\n";
		return false;
	}
	// compilation error
	cout << "compilation error : First word in jack file must be 'class' \n";
	return false;
}

// handle class var declarations
bool CompilationEngine::CompileClassVarDec()
{
	// Variable kind - static/field. Stored for each variable symbol
	string	varKind;
	// Variable type - int/char/boolean. Stored for each variable symbol
	string varType;

	//start parsing:
	string next=tokenizerInstance.getTokenizedFile();
	next.erase(0,tokenizerInstance.getTokenPtr());
	string currentToken=next;
	// erase string to check if "static" is next word
	currentToken.erase(6,currentToken.size()-6);
	if(currentToken!="static")
		// erase string to check if "field" is next word
		currentToken.erase(5,1);

	// handle the vars
	if(currentToken=="static"||currentToken=="field")
	{
		
		varKind=currentToken;
		// increment ptr to next token
		tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+currentToken.size());
		next.erase(0,currentToken.size());
		currentToken=next;
		// erase from next space to the end
		currentToken.erase(currentToken.find(" "), currentToken.size()-currentToken.find(" "));
		tokenizerInstance.setCurrentToken(currentToken);
		// check token type
		if(tokenizerInstance.tokenType()==IDENTIFIER||currentToken=="int"||currentToken=="char"||currentToken=="boolean")
		{
			// save the variable type
			varType=currentToken;

			// inc to next token
			tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+(currentToken.size()+1));
			next.erase(0,(currentToken.size()+1));
			currentToken=next;
			// get only current line (stop at ;)
			currentToken.erase(currentToken.find(";"),currentToken.size()-currentToken.find(";"));
			tokenizerInstance.setCurrentToken(currentToken);
			// we want to know if we got identifier or complex text
			if(tokenizerInstance.tokenType()==OTHER)
				// if not identifier cut from next comma
				currentToken.erase(currentToken.find(","),currentToken.size()-currentToken.find(","));
			tokenizerInstance.setCurrentToken(currentToken);
			if(tokenizerInstance.tokenType()==IDENTIFIER)
			{
				//Store this var in the class scope symbol table
				CSTab.define(currentToken,varType,varKind);
				tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+currentToken.size());
				next.erase(0,currentToken.size());
			}
			// handle all symbols and identifires till ; eol
			while(next[0]==',')
			{	
				tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
				next.erase(0,1);
				currentToken=next;
				currentToken.erase(currentToken.find(" "),currentToken.size()-currentToken.find(" "));
				tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
				next.erase(0,1);
				if(tokenizerInstance.tokenType()==IDENTIFIER)
				{
					CSTab.define(currentToken,varType,varKind);
					tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+currentToken.size());
					next.erase(0,currentToken.size());
				}
			}
			// we got to the eol ;
			if(next[0]==';')
			{
				tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
				// everything is Good
				return true;
			}
			// line didnt end with ;
			cout << "compilation error : did you forget ; eol ?\n";
			return false;
		}
		// no match keyword
		cout << "compilation error : identifier error\n";
		return false ;
	}
	// no vars to handle (and its ok!)
	return true;
}

// compile the rutines
bool CompilationEngine::CompileSubroutine()
{
	// Subroutine kind - method/function/constructor. Stored for each subroutine symbol
	string subKind;
	// Subroutine return type - void/int/char/boolean. Stored for each subroutine symbol
	string subType;
	// Subroutine name - IDENTIFIER. this is the actual subroutine symbol
	string subName;

	//Initialize a "mthod scope" symbol table for this subroutine
	MSTab.startnewSubroutine();
	
	//start parsing:
	string next=tokenizerInstance.getTokenizedFile();
	next.erase(0,tokenizerInstance.getTokenPtr());
	string currentToken=next;
	// erase end of string to match "constructor" length
	currentToken.erase(11,currentToken.size()-11);
	// if its not constructor we cut even more...
	if(currentToken!="constructor")
	{
		currentToken=next;
		// cut the string to match "function"
		currentToken.erase(8,currentToken.size()-8);
		if(currentToken!="function"){
			currentToken=next;
			// not constructor/function , it must be "method" cut more!
			currentToken.erase(6,currentToken.size()-6);
		}
	}
	// are we handling a subrutine?
	if(currentToken=="constructor"||currentToken=="method"||currentToken=="function")
	{
		// save sub kind
		subKind=currentToken;
		// continue parsing
		tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+currentToken.size());
		next.erase(0,currentToken.size());
		currentToken=next;
		currentToken.erase(currentToken.find(" "), currentToken.size()-currentToken.find(" "));
		tokenizerInstance.setCurrentToken(currentToken);

		// get the identifier/
		if(tokenizerInstance.tokenType()==IDENTIFIER||currentToken=="int"||currentToken=="char"||currentToken=="boolean"||currentToken=="void")
		{
			subType=currentToken; //Don't actually do much with this in jack... :)
			
			// advance parsing
			tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+currentToken.size()+1);
			next.erase(0,(currentToken.size()+1));
			currentToken=next;
			currentToken.erase(currentToken.find("("),currentToken.size()-currentToken.find("("));
			tokenizerInstance.setCurrentToken(currentToken);
			
			// get the identifier
			if(tokenizerInstance.tokenType()==IDENTIFIER){
				// save subroutine name
				subName = currentToken;
				tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+currentToken.size()+1);
				next.erase(0,(currentToken.size()+1));
			}

			// Methods always have "n+1" arguments, including 'this'
			if(subKind=="method") 
				MSTab.argCount=1;

			// compile the parameters list! 
			if (!CompileParameterList())
			{
				// no match identifier
				cout << "compilation error : identifier error\n";
				return false;
			}

			next=tokenizerInstance.getTokenizedFile();
			next.erase(0,tokenizerInstance.getTokenPtr());
			// are we at the end of the bracket? (parameters)
			if(next[0]==')')
			{
				tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
				next.erase(0,1);
			}
			// get the bracket begining the subrutine
			if(next[0]=='{')
			{
				tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
				next.erase(0,1);
			}

			// compile all var dec
			while(CompileVarDec());

			// produce actual "function" vm statement
			outfile << "function " << className << "." << subName << " " << MSTab.varCount << endl;

			// class methods need "this" initialization:
			if(subKind=="method")
				outfile << "push argument 0\npop pointer 0\n";
			// and constructors need dynamic memory allocation:
			else if(subKind=="constructor"){
				outfile << "push constant " << CSTab.fieldCount << endl
					<< "call Memory.alloc 1\npop pointer 0\n";
			}
			
			// continue parsing
			next=tokenizerInstance.getTokenizedFile();
			next.erase(0,tokenizerInstance.getTokenPtr());
			
			// compile the actual subroutine body, which is all statements:
			CompileStatements();
			
			next=tokenizerInstance.getTokenizedFile();
			next.erase(0,tokenizerInstance.getTokenPtr());
			
			// expecting end of block here
			if(next[0]=='}')
			{
				
				tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
				if(next[0]==' ') 
					tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
				// routine compiled successfully!
				return true;
			}
			// missing closing bracket
			cout << "compilation error : are you missin } ?\n";
			return false;
		}
		// no match keyword
		cout << "compilation error : identifier error\n";
		return false;
	}
	// no subrutines to compile (and its OK!)
	return true;
}

// compile the parameters list of subroutine
bool CompilationEngine::CompileParameterList()
{
	// Variable kind - always 'arg' in arg list... Stored for each variable symbol
	string varKind;
	// Variable type - int/char/boolean. Stored for each variable symbol
	string varType;

	// parsing variables:
	string currentToken;

	//start parsing:
	string next=tokenizerInstance.getTokenizedFile();
	next.erase(0,tokenizerInstance.getTokenPtr());
	// if no params return
	if(next[0]==' '&&next[1]==')'){ 
		tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+2); 
		return true;
	}
	// arguments list always have arguments...
	varKind="arg";

	// handle all params till next char is not ","
	do{
		// add symbol if we got to ","
		if(next[0]==',')
		{
			tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
			next.erase(0,1);
		}
		currentToken=next;
		// find the next space and erase from it
		currentToken.erase(currentToken.find(" "), currentToken.size()-currentToken.find(" "));
		tokenizerInstance.setCurrentToken(currentToken);

		// it must be identifier or type
		if(tokenizerInstance.tokenType()==IDENTIFIER||currentToken=="int"||currentToken=="char"||currentToken=="boolean")
		{
			// save argument type
			varType = currentToken;
			// cont. parsing
			tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+currentToken.size()+1);
			next.erase(0,(currentToken.size()+1));
			currentToken=next;
			// is there an ',' at the end?
			if(currentToken.find(",")<currentToken.size())
				currentToken.erase(currentToken.find(","), currentToken.size()-currentToken.find(","));
			tokenizerInstance.setCurrentToken(currentToken);
			// if its just an identifier
			if(tokenizerInstance.tokenType()==IDENTIFIER){
				// add symbol to method scope symbol table
				MSTab.define(currentToken,varType,varKind);
				tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+currentToken.size());
				next.erase(0,currentToken.size());
			}
			// not identifier
			else //identifier and trailing ')'
			{
				currentToken=next;
				currentToken.erase(currentToken.find(")"), currentToken.size()-currentToken.find(")"));
				tokenizerInstance.setCurrentToken(currentToken);
				// it must be identifier next
				if(tokenizerInstance.tokenType()==IDENTIFIER)
				{
					 MSTab.define(currentToken,varType,varKind);
					tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr() +currentToken.size());
					next.erase(0,currentToken.size());
				}
				//error identifier
				else 
				{
					cout << "compilation error : identifier error\n";
					return false;
				}
			}
		}
		// error identifier
		else 
		{
			cout << "compilation error : identifier error\n";
			return false;
		}
		// next is comma so continue, or we're done
	} while(next[0]==',');
	// All done!
	return true;
}

// compile the variable decleration
bool CompilationEngine::CompileVarDec()
{
	// Variable kind - always 'var' inside method. Stored for each variable symbol
	string	varKind;
	// Variable type - int/char/boolean. Stored for each variable symbol
	string varType;
	
	//start parsing:
	string next=tokenizerInstance.getTokenizedFile();
	next.erase(0,tokenizerInstance.getTokenPtr());
	string currentToken=next;
	currentToken.erase(3,currentToken.size()-3);
	
	// are we handling var?
	if(currentToken=="var")
	{
		varKind = currentToken;
		tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+currentToken.size());
		next.erase(0,currentToken.size());
		currentToken=next;
		currentToken.erase(currentToken.find(" "), currentToken.size()-currentToken.find(" "));
		tokenizerInstance.setCurrentToken(currentToken);

		// Expects a type and identifier(s)
		if(tokenizerInstance.tokenType()==IDENTIFIER||currentToken=="int"||currentToken=="char"||currentToken=="boolean")
		{
			// save the variable type
			varType = currentToken;

			// inc to next token
			tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+currentToken.size()+1);
			next.erase(0,(currentToken.size()+1));
			currentToken=next;
			// get only current line (stop at ;)
			currentToken.erase(currentToken.find(";"),currentToken.size()-currentToken.find(";"));
			tokenizerInstance.setCurrentToken(currentToken);
			if(tokenizerInstance.tokenType()!=IDENTIFIER)
				currentToken.erase(currentToken.find(","),currentToken.size()-currentToken.find(","));
			tokenizerInstance.setCurrentToken(currentToken);
			if(tokenizerInstance.tokenType()==IDENTIFIER)
			{
				//Store this var in the method scope symbol table
				MSTab.define(currentToken,varType,varKind);

				tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr() +currentToken.size());
				next.erase(0,currentToken.size());
			}
			//in case more than one identifier, we expect ','
			while(next[0]==',')
			{	
				tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
				next.erase(0,1);
				currentToken=next;
				currentToken.erase(currentToken.find(" "),currentToken.size()-currentToken.find(" "));
				tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
				next.erase(0,1);
				if(tokenizerInstance.tokenType()==IDENTIFIER)
				{
					//Store this var in the method scope symbol table
					MSTab.define(currentToken,varType,varKind);
					tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr() +currentToken.size());
					next.erase(0,currentToken.size());
				}
			}
			// expects a ';'
			if(next[0]==';')
			{
				tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
				return true;
			}
			cout << "compilation error : ; expected\n";
			return false;
		}
		cout << "compilation error : type expected\n";
		return false;
	}
	// no vars to compile (and its OK!)
	return false;
}

// compile all statements in a jack code block
bool CompilationEngine::CompileStatements()
{
	// copile any statement. Specifically, one of 'let', 'do', 'if', 'while'
	while(CompileLet()||CompileDo()||CompileIf()||CompileWhile());
	// blocks of statements are expected, until finally there's 'return'
	CompileReturn();
	// All Done!
	return true;
}

// compile a "do ..." statement
bool CompilationEngine::CompileDo()
{

	//start parsing:
	string next=tokenizerInstance.getTokenizedFile();
	next.erase(0,tokenizerInstance.getTokenPtr());
	string currentToken=next;
	currentToken.erase(2,currentToken.size()-2);
	// is this really a "do" statement?
	if(currentToken=="do")
	{         
		tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+currentToken.size());
		//"do" expected before subroutine call
		if(CompileSubroutineCall()){
			next=tokenizerInstance.getTokenizedFile();
			next.erase(0,tokenizerInstance.getTokenPtr());
			//expects ';'
			if(next[0]==';')
			{
				tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
				outfile << "pop temp 6\n"; //Return value is actually discarded.
				                           //but we need stack housekeeping...
				return true;
			}
			// compilation error
			cout << "compilation error : ; expected \n";
			return false;			
		}
		// compilation error
		cout << "compilation error : subroutine call expected\n";
		return false;
	}
	//No 'do' here! And it's ok... just return false...
	return false;
}

// compile a "function(params)" statement
bool CompilationEngine::CompileSubroutineCall()
{
	//Counter for number of arguments being passed:
	int numOfArgs=0;

	//start parsing:
	string next=tokenizerInstance.getTokenizedFile();
	next=tokenizerInstance.getTokenizedFile();
	next.erase(0,tokenizerInstance.getTokenPtr());

	bool isLooksLikeMethodCall = false; //Syntax is string.otherstring
	
	string currentToken=next;
	//handle Class.function syntax
	if(currentToken.find(".")<currentToken.size())
		currentToken.erase(currentToken.find("."), currentToken.size()-currentToken.find("."));
	tokenizerInstance.setCurrentToken(currentToken);
	//Expecting an identifier
	if(tokenizerInstance.tokenType()==IDENTIFIER)
	{
		tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+currentToken.size()+1);
		next.erase(0,currentToken.size()+1);
		isLooksLikeMethodCall = true;
	}

	string currentToken1=next;
	//Expecting function call with '('
	currentToken1.erase(currentToken1.find("("), currentToken1.size()-currentToken1.find("("));
	tokenizerInstance.setCurrentToken(currentToken1);
	if(tokenizerInstance.tokenType()==IDENTIFIER)
	{
		tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+currentToken1.size()+1);
		next.erase(0,currentToken1.size()+1);
		if(isLooksLikeMethodCall) //Function call looks something like <something>.<somethingelse>
		{
			//Check if currentToken is a known symbol:
			if(CSTab.searchSymbol(currentToken)||MSTab.searchSymbol(currentToken))
			{
				if ( CSTab.searchSymbol(currentToken) )	{   
					//currentToken is known as a class scope identifier
					tokenizerInstance.setCurrentToken(CSTab.typeOf(currentToken));
				} else	{   
					//currentToken is known as a Method scope identifier
					tokenizerInstance.setCurrentToken(MSTab.typeOf(currentToken));
				}

				if(tokenizerInstance.tokenType()==IDENTIFIER)
				{ //This is an identifier
					if (CSTab.searchSymbol(currentToken)) { 
						//Identifier is class scope. Push it for 'this'
						CSTab.writePushPop(currentToken, outfile, true);
					} else {
						//Identifier is method scope. Push it for 'this'
						MSTab.writePushPop(currentToken, outfile, true);
					}
					numOfArgs++; //This is a real method, add "this" to args count
				} else {
					cout << currentToken << " is not an object and cannot invoke a method\n";
					exit(0);
				}
				currentToken=tokenizerInstance.getCurrentToken();
			}
			currentToken1=(currentToken+"."+currentToken1);
		}
		else{ // in Jack - anything which doesn't look like class.function is "local" 
			  // method inside the same class. So we need to push 'this'
			outfile << "push pointer 0\n";
			currentToken1=(className+"."+currentToken1);
			numOfArgs++; //This is a real method, add "this" to args count
		}
	}
	else return false;
	//parse parameters list:
	if(next[0]==' ')
	{
		tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
		next.erase(0,1);
	}

	//Simple () call - are we done?
	if(next[0]==')')
	{
		//Actually generate the "call" statement:
		outfile << "call " << currentToken1 << " " << numOfArgs << endl;
		tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
		return true;
	}

	//Is there an expression as an argument to the subbroutine?
	if(CompileExpression())
	{
		next=tokenizerInstance.getTokenizedFile();
		next.erase(0,tokenizerInstance.getTokenPtr());
		if(next[0]==' ')
		{
			tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
			next.erase(0,1);
		}
		//Is this expression the end of the arg list?
		if(next[0]==')')
		{
			numOfArgs++; //The extra expression, "is already on stack"
			outfile << "call " << currentToken1 << " " << numOfArgs << endl;
			tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
			next.erase(0,1);
			return true;
		}
	}
	
	//more than one pareams in list:
	while(next[0]==',')
	{
		// ',' is parameter separator
		if(next[0]==',')
		{
			numOfArgs++;
			tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
			next.erase(0,1);
			if(next[0]==' ')
			{
				tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
				next.erase(0,1);
			}
		}
		//parameter clause is an expression:
		if(CompileExpression())
		{
			next=tokenizerInstance.getTokenizedFile();
			next.erase(0,tokenizerInstance.getTokenPtr());
			if(next[0]==' ')
			{
				tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
				next.erase(0,1);
			}
			//Is this the expression the last argument?
			if(next[0]==')')
			{
				numOfArgs++;
				//actually generate the "call" statement
				outfile << "call " << currentToken1 << " " << numOfArgs << endl;
				tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
				next.erase(0,1);
				return true;
			}
		}
	}
	//Exiting here means this is not a subroutine call. 
	return false;
}

// compile a "let ..." statement
bool CompilationEngine::CompileLet()
{
	//start parsing:
	string next=tokenizerInstance.getTokenizedFile();
	next.erase(0,tokenizerInstance.getTokenPtr());
	string currentToken=next;
	currentToken.erase(3,currentToken.size()-3);
	bool foundArray=false;
	//are we really in "let" statement?
	if(currentToken=="let")
	{     
		tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+3);
		next.erase(0,3);
		currentToken=next;
		//deal with Array[ syntax:
		if(currentToken.find("[")<currentToken.size())
		{
			currentToken.erase(currentToken.find("["), currentToken.size()-currentToken.find("["));
			tokenizerInstance.setCurrentToken(currentToken);
			if(tokenizerInstance.tokenType()==IDENTIFIER) foundArray=true;
		}

		if(foundArray)
		{
			tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+currentToken.size()+1);
			next.erase(0,currentToken.size()+1);
			//Expecting an expression within [...]
			if(CompileExpression()){ //Expression result "left" on the stack
				outfile << "pop temp 7\n";  //get it to temp 7
				next=tokenizerInstance.getTokenizedFile();
				next.erase(0,tokenizerInstance.getTokenPtr());
				if(next[0]==']'&&next[1]=='='){
					
					tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+2);
					next.erase(0,2);
					//Expecting the RHS of 'let var = expression'
					if(CompileExpression()){ 
						next=tokenizerInstance.getTokenizedFile();
						next.erase(0,tokenizerInstance.getTokenPtr());
						if(next[0]==';')
						{
							tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
							// Find symbol in symbol table and push the address:
							if(MSTab.searchSymbol(currentToken))
								MSTab.writePushPop(currentToken, outfile, true);
							else if(CSTab.searchSymbol(currentToken))
								CSTab.writePushPop(currentToken, outfile, true);
							else { 
								cout << "Undeclared variable " << currentToken << endl; 
								exit(0);
								}
							//Calculate "array" memory access using the offset saved in temp 7
							//and the "base" pushed from the symbol table. This is popped into 
							//pointer 1, and the value is popped into that 0.
							outfile << "push temp 7\nadd\npop pointer 1\npop that 0\n";

							return true;
						}
						cout << "compilation error : ; expected\n";

					}
					cout << "compilation error : expression expected\n";

				}
				cout << "compilation error : ]= expected\n";

			}
			cout << "compilation error : [expression] expected\n";
		}
		else
		{ //Not Array[ ...
			currentToken=next;
			currentToken.erase(currentToken.find("="), currentToken.size()-currentToken.find("="));
			tokenizerInstance.setCurrentToken(currentToken);
			//Expecting 'identifier = ...'
			if(tokenizerInstance.tokenType()==IDENTIFIER)
			{
				tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+currentToken.size()+1);
				next.erase(0,currentToken.size()+1);
				//Expecting the RHS of 'let var = expression'
				if(CompileExpression())
				{                                                
					next=tokenizerInstance.getTokenizedFile();
					next.erase(0,tokenizerInstance.getTokenPtr());
					if(next[0]==';')
					{
						tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
						// TBD Added

						if(MSTab.searchSymbol(currentToken))
							MSTab.writePushPop(currentToken, outfile, false);
						else if(CSTab.searchSymbol(currentToken))
							CSTab.writePushPop(currentToken, outfile, false);
						else{ cout << "Undeclared variable " << currentToken << endl; exit(0);}

						//////


						return true;
					}
					cout << "compilation error : ; expected\n";
				}
				cout << "compilation error : expression expected\n";
			}
			cout << "compilation error : identifier expected\n";
		}
		//Can't get here...
	}
	//Not reallt a 'let' statement, which is Ok
	return false;
}


// compile a "while () { }statement
bool CompilationEngine::CompileWhile()
{
	//start parsing:
	string next=tokenizerInstance.getTokenizedFile();
	next.erase(0,tokenizerInstance.getTokenPtr());
	string currentToken=next;
	currentToken.erase(5,currentToken.size()-5);
	//Is this really a "while" statement?
	if(currentToken=="while")
	{
		tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+currentToken.size());
		next.erase(0,currentToken.size());
		//Expecting ( expression ) 
		if(next[0]=='(')
		{
			tokenizerInstance.eraseNextSpace(next);
			tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
			next.erase(0,1);
			// generate label for beginning of loop:
			int currentWhileID=whileCount++;
			outfile << "label while_loop_" << currentWhileID << endl;

			///////////////
			if(CompileExpression())
			{
				next=tokenizerInstance.getTokenizedFile();
				next.erase(0,tokenizerInstance.getTokenPtr());
				//Expecting ') { ...'
				if(next[0]==')'&&next[1]=='{')
				{
					// generate conditional jump out of loop if "cond" (on stack) isn't met:
					outfile << "not\nif-goto end_while_" << currentWhileID << endl;

					//continue parsing
					tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+2);
					next.erase(0,2);
					//Compile any statements within this block
					if(CompileStatements())
					{
						next=tokenizerInstance.getTokenizedFile();
						next.erase(0,tokenizerInstance.getTokenPtr());
						//until '}'
						if(next[0]=='}')
						{
							// generate code for actual jump to beginning of loop
							outfile << "goto while_loop_" << currentWhileID << endl;
							// and label for exiting the loop
							outfile	<< "label end_while_" << currentWhileID << endl;

							//clean parsing
							tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
							next.erase(0,1);
							//and we're done!
							return true;
						}
						cout << "compilation error : } expected\n";
					}
					//No statements, and this is Ok!
					return true;
				}
				cout << "compilation error : ) { expected\n";
			}
			cout << "compilation error : expression expected\n";

		}
		cout << "compilation error : ( expected\n";
	} 
	return false;
}

// compile a "return (value)statement
bool CompilationEngine::CompileReturn()
{
	//start parsing:
	string next=tokenizerInstance.getTokenizedFile();
	next.erase(0,tokenizerInstance.getTokenPtr());
	string currentToken=next;
	currentToken.erase(6,currentToken.size()-6);

	//Is this really a 'return'?
	if(currentToken=="return")
	{         
		tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+currentToken.size());
		next=tokenizerInstance.getTokenizedFile();
		next.erase(0,tokenizerInstance.getTokenPtr());
		//if no ';', expect an expression for return value.
		if(next[0]!=';')
		{
			if(CompileExpression())
			{
				//Expression value was left on stack...
				next=tokenizerInstance.getTokenizedFile();
				next.erase(0,tokenizerInstance.getTokenPtr());
			}
			else
			{
				cout << "compilation error : expression expected\n";
			}
		} 
		else outfile << "push constant 0\n";
		//Expression value "faked" on stack... return will expect it to be there...

		//if ';' - done
		if(next[0]==';')
		{
			//generate actual return code
			outfile << "return\n";
			//cleanup parsing
			tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
			next.erase(0,1);
			return true;
		}
		cout << "compilation error : ; expected\n";

	}
	//Not 'return', and it's ok.
	return false;
}

// compile a 'if (cond) {...}' statement
bool CompilationEngine::CompileIf()
{
	//start parsing:
	string next=tokenizerInstance.getTokenizedFile();
	next.erase(0,tokenizerInstance.getTokenPtr());
	string currentToken=next;
	currentToken.erase(2,currentToken.size()-2);
	//Is this really an 'if'?
	if(currentToken=="if")
	{   
		tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+currentToken.size());
		next.erase(0,currentToken.size());
		//expects '( ...'
		if(next[0]=='(')
		{
			tokenizerInstance.eraseNextSpace(next);
			tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
			next.erase(0,1);
			//condition is an expression
			if(CompileExpression())
			{
				next=tokenizerInstance.getTokenizedFile();
				next.erase(0,tokenizerInstance.getTokenPtr());
				//expects ') { ... } '
				if(next[0]==')'&&next[1]=='{')
				{
					int currentIfID=ifCount++;
					//Generate code to jump to end of "then" clause if cond (on stack) is false
					outfile << "not\nif-goto else_" << currentIfID << endl;
					tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+2);
					next.erase(0,2);
					//Compile any statements in this block
					if(CompileStatements())
					{
						next=tokenizerInstance.getTokenizedFile();
						next.erase(0,tokenizerInstance.getTokenPtr());
						if(next[0]=='}') //Must end by '}'
						{
							tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
							next.erase(0,1);
							currentToken=next;
							currentToken.erase(4,currentToken.size()-4);
							//Optionally "else" clause exists.
							if(currentToken=="else"&&next[4]=='{')
							{
								//Generate code to jump to the end of the 'if-then-else' clause
								//since we executed the "then" part
	                            outfile << "goto end_if_" << currentIfID << endl;
								outfile << "label else_" << currentIfID << endl;
								tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+5);
								next.erase(0,5);
								if(CompileStatements())
								{
									next=tokenizerInstance.getTokenizedFile();
									next.erase(0,tokenizerInstance.getTokenPtr());
									if(next[0]=='}')
									{
										tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
										next.erase(0,1);
									}
								}
								//End label for the whole if-then-else statement
	                            outfile << "label end_if_" << currentIfID << endl;
							}
							else 
							{
								//If there's no "else" clause, ELSE and ENDIF are the same...
								//Only need ELSE...
								outfile << "label else_" << currentIfID << endl;
							}
							return true;              
						}
						cout << "compilation error : } expected\n";
					}
					//no statements, and that's Ok!
					return true;
				}
				cout << "compilation error : ) { expected\n";
			}
			cout << "compilation error : expression expected\n";
		}
		cout << "compilation error : ( expected\n";

	}
	//Not 'if' and it's ok...
	return false;     
}

// compile a complex expression
bool CompilationEngine::CompileExpression()
{
	//start parsing:
	string next=tokenizerInstance.getTokenizedFile();
	next.erase(0,tokenizerInstance.getTokenPtr());

	if(CompileTerm())
	{
		next=tokenizerInstance.getTokenizedFile();
		next.erase(0,tokenizerInstance.getTokenPtr());
		while(next[0]==' ')
		{
			tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1); 
			next.erase(0,1);
		}
		while(isMathOperation(next[0]))
		{
			//Actually generate code for basic math operations:
			//First operator is already assumed on stack
			char opr=next[0];
			tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
			next.erase(0,1);
			//Expecting a term after this, as second operand
			if(CompileTerm())
			{
				next=tokenizerInstance.getTokenizedFile();
				next.erase(0,tokenizerInstance.getTokenPtr());
			}
			else 
				return false; //TBD: This is an error?

			//The operator itself:
			switch(opr){
			case '+':   outfile << "add\n";
				break;
			case '-':   outfile << "sub\n";
				break;
			case '*':   outfile << "call Math.multiply 2\n";
				break;
			case '/':   outfile << "call Math.divide 2\n";
				break;
			case '&':   outfile << "and\n";
				break;
			case '|':   outfile << "or\n";
				break;
			case '<':   outfile << "lt\n";
				break;
			case '>':   outfile << "gt\n";
				break;
			case '=':   outfile << "eq\n";
				break;
			}
		}
		return true;
	}
	//No terms in this expression, which makes an empty expression. Sometimes ok...
	return false;
}

// compile a term within an expression
bool CompilationEngine::CompileTerm()
{
	//start parsing:
	string next=tokenizerInstance.getTokenizedFile();
	next.erase(0,tokenizerInstance.getTokenPtr());

	bool foundTerm=false;

	string currentToken=next,currentToken1=next;
	currentToken.erase(4,currentToken.size()-4);
	currentToken1.erase(5,currentToken1.size()-5);
	if(currentToken1=="false") currentToken="false";
	if(currentToken=="true"||currentToken=="null"||currentToken=="this"||currentToken=="false")
	{
		//generate code for "constants:
		//0 is both null and false
		if(currentToken=="null"||currentToken=="false") outfile << "push constant 0\n"; 
		//-1 is 'true'
		else if(currentToken=="true") outfile << "push constant 1\nneg\n";
		//pointer 0 is 'this'
		else outfile << "push pointer 0\n";
		tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+currentToken.size());
		foundTerm=true;
	}
	else if(next[0]=='(')
	{
		//Deal with ()
		tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
		next.erase(0,1);
		if(next[0]==' ')
		{
			tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1); 
			next.erase(0,1);
		}
		//Recursively deal with an expression
		if(CompileExpression())
		{
			next=tokenizerInstance.getTokenizedFile();
			next.erase(0,tokenizerInstance.getTokenPtr());
			if(next[0]==' ')
			{
				next.erase(0,1); 
				tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
			}
			if(next[0]==')')
			{
				tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
				next.erase(0,1);
				foundTerm=true;
			} else {
				cout << "compilation error : ) expected\n";
			}
		}
		//Expression can possibly be empty...
	}
	else if(next[0]=='~'||next[0]=='-')
	{
		//Deal with unary operators
		char opr=next[0];
		tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
		next.erase(0,1);
		if(CompileTerm()){
			foundTerm = true;
			if(opr=='~') outfile << "not\n";
			else outfile << "neg\n";
		} else {
			cout << "compilation error : expression expected\n";
		}
	}
	else if(next[0]=='\"')
	{
		//Deal with string constants
		tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
		next.erase(0,1);
		currentToken=next;
		currentToken.erase(currentToken.find("\""),currentToken.size()-currentToken.find("\""));
		string currentToken1=currentToken;
		currentToken="";
		
		for(unsigned int i=0;i<currentToken1.size();i++)
			if(currentToken1[i]!='^') currentToken+=currentToken1[i];
		//Strings are impleleted by iteratively calling 'appendChar' with conastants
		//representing the chars of the string:
		//Get a new string of size currentToken.size():
		outfile << "push constant " << currentToken.size() << endl
			<< "call String.new 1\n";
		//append each char in its turn:
		for(unsigned int i=0;i<currentToken.size();i++){
			outfile << "push constant " << (int)(currentToken[i]) << endl
				<< "call String.appendChar 2\n";
		}
		tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+currentToken1.size()+1);
		next.erase(0,currentToken1.size()+1);
		foundTerm=true;
	}
	else if(isdigit(next[0]))
	{
		//Deal with numbers:
		currentToken=next;
		currentToken.erase(currentToken.find("@"),currentToken.size()-currentToken.find("@"));
		tokenizerInstance.setCurrentToken(currentToken);
		if(tokenizerInstance.tokenType()==INT_CONST)
		{
			//Just push the value onto the stack:
			outfile << "push constant " << tokenizerInstance.intVal() << endl;
			tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+currentToken.size()+1);
			next.erase(0,currentToken.size()+1);
			foundTerm=true;
		}
	}
	else
	{
		//deal with identifiers
		currentToken="";
		for(int i=0;(isalnum(next[i])||next[i]=='_')&&(!isdigit(next[0]));i++)
			currentToken+=next[i];
		if(currentToken.size()>0&&next[currentToken.size()]!='('&&next[currentToken.size()]!='.')
		{
			//Make sure the identifier is valid: lookup in symtab:
			if(MSTab.searchSymbol(currentToken))
				MSTab.writePushPop(currentToken, outfile, true);
			else if(CSTab.searchSymbol(currentToken))
				CSTab.writePushPop(currentToken, outfile, true);
			else{ cout << "Undeclared variable " << currentToken << endl; exit(0);}

			tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+currentToken.size());
			next.erase(0,currentToken.size());
			foundTerm=true;
			
			if(next[0]==' ')
			{
				tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
				next.erase(0,1);
			}

			if(next[0]=='[')
			{ //deal with arrays
				tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
				next.erase(0,1);
				if(CompileExpression()){
					next=tokenizerInstance.getTokenizedFile();
					next.erase(0,tokenizerInstance.getTokenPtr());
					if(next[0]==']')
					{
						//generate code to access the array:
						outfile << "add\npop pointer 1\npush that 0\n";
						tokenizerInstance.setTokenPtr(tokenizerInstance.getTokenPtr()+1);
						next.erase(0,1);
					}
					else foundTerm=false;
				}
				else foundTerm=false;
			}
		}
		else if(CompileSubroutineCall())
		{	//deal with subroutine call embedded into expression:
			next=tokenizerInstance.getTokenizedFile();
			next.erase(0,tokenizerInstance.getTokenPtr());
			foundTerm=true;
		}
	}
	if(foundTerm)
	{
		return true;
	}
	//No actualy term to compile:
	return false;
	
}

